from PySide6.QtWidgets import QApplication, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QFileDialog, QWidget, \
    QVBoxLayout, QPushButton
from PySide6.QtGui import QPixmap, QImage, QWheelEvent
from PySide6.QtUiTools import QUiLoader
from PySide6.QtCore import Qt, QPointF, QRectF
import cv2 as cv
import numpy as np
import sys
#image_global = None
filename_global = None

class CustomGraphicsView(QGraphicsView): #自定义画板
    def __init__(self, parent=None):
        super(CustomGraphicsView, self).__init__(parent)
        self.scene = QGraphicsScene(self)
        self.setScene(self.scene)
        self.pixmap_item = None #存储图片
        self.scale_factor = 1.0 #缩放因子
        self.is_dragging = False#是否正在拖拽
        self.drag_start_pos = None#存储拖拽开始的位置
        self.last_mouse_position = QPointF()#存储鼠标的最后一个位置

    def set_image(self, image_path): #加载图片
        # 加载图片并设置到场景中
        pixmap = QPixmap(image_path)
        self.pixmap_item = QGraphicsPixmapItem(pixmap)
        self.scene.addItem(self.pixmap_item)
        self.scene.setSceneRect(pixmap.rect())
        self.fit_in_view()  # 初始时适应视图大小

    def fit_in_view(self):
        # 使图片适应视图大小，保持宽高比
        rect = self.scene.sceneRect()
        if not rect.isNull():
            self.setSceneRect(rect)
            unity = self.transform().mapRect(QRectF(0, 0, 1, 1))
            self.scale(1 / unity.width(), 1 / unity.height())
            viewrect = self.viewport().rect()
            xratio = viewrect.width() / rect.width()
            yratio = viewrect.height() / rect.height()
            self.scale(min(xratio, yratio), min(xratio, yratio))

    def wheelEvent(self, event: QWheelEvent):
        # 处理滚轮事件以实现缩放
        zoom_in_factor = 1.25
        zoom_out_factor = 1 / zoom_in_factor

        # 获取滚轮的方向
        if event.angleDelta().y() > 0:
            zoom_factor = zoom_in_factor
        else:
            zoom_factor = zoom_out_factor

        # 计算新的缩放因子，但不超过一定的限制
        self.scale_factor *= zoom_factor
        self.scale_factor = min(max(0.1, self.scale_factor), 10.0)  # 限制缩放范围在0.1到10之间

        # 应用缩放
        self.scale(zoom_factor, zoom_factor)

    def mousePressEvent(self, event):
        super().mousePressEvent(event)
        # 处理鼠标按下事件以开始拖动
        print("检测到点击0")
        if event.button() == Qt.LeftButton:
            print("检测到点击1")
            self.drag_start_pos = event.position().toPoint()  # 使用 position() 并转换为 QPoint
            self.is_dragging = True

    def mouseMoveEvent(self, event):
        if self.is_dragging:
            print("检测到drag")
            delta = event.position().toPoint() - self.drag_start_pos
            self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() - delta.x())
            self.verticalScrollBar().setValue(self.verticalScrollBar().value() - delta.y())
            self.drag_start_pos = event.position().toPoint()  # 更新拖动起始位置

    def mouseReleaseEvent(self, event):
        # 处理鼠标释放事件以停止拖动
        if event.button() == Qt.LeftButton:
            self.is_dragging = False

class ImageViewer:
    def __init__(self, graphics_view):
        loader = QUiLoader()
        self.ui = loader.load("imageViewer.ui")
        self.ui.setWindowTitle("Image Viewer")

        self.graphics_view = graphics_view
        self.scene = QGraphicsScene(self.graphics_view)
        self.ui.graphicsView.setScene(self.scene)

        self.pixmap_item = QGraphicsPixmapItem()
        self.scene.addItem(self.pixmap_item)

        self.image_original = None  # 原始图片
        self.image_current = None  # 当前操作的图片
        self.is_gray = False  # 标志是否为灰度化状态

        # 按钮绑定功能
        self.ui.button_open.clicked.connect(self.open_image)
        self.ui.button_gray.clicked.connect(self.toggle_gray)
        self.ui.button_invert.clicked.connect(self.invert_color)
        self.ui.button_rotate1.clicked.connect(lambda: self.rotate_image(-90))
        self.ui.button_rotate2.clicked.connect(lambda: self.rotate_image(90))
        self.ui.graphicsView.setSceneRect(self.pixmap_item.boundingRect())
        self.ui.button_newwin.clicked.connect(self.showNewWindow)

    def open_image(self):
        file_path, _ = QFileDialog.getOpenFileName(
            None, "Open Image", "", "Image Files (*.png *.jpg *.jpeg *.bmp)"
        )
        if file_path:
            self.image_original = cv.imread(file_path)
            self.image_current = self.image_original.copy()
            global filename_global
            filename_global = file_path
            self.is_gray = False  # 重置灰度状态
            self.display_preview()
            self.display_graphics_view()

    def display_preview(self):
        if self.image_original is not None:
            image_rgb = cv.cvtColor(self.image_original, cv.COLOR_BGR2RGB)
            h, w, ch = image_rgb.shape
            bytes_per_line = ch * w
            q_image = QImage(image_rgb.data, w, h, bytes_per_line, QImage.Format_RGB888)
            pixmap = QPixmap.fromImage(q_image)
            self.ui.label.setPixmap(pixmap.scaled(self.ui.label.size(), Qt.KeepAspectRatio))

    def display_graphics_view(self):
        if self.image_current is not None:
            image_rgb = cv.cvtColor(self.image_current, cv.COLOR_BGR2RGB)
            h, w, ch = image_rgb.shape
            bytes_per_line = ch * w
            q_image = QImage(image_rgb.data, w, h, bytes_per_line, QImage.Format_RGB888)
            pixmap = QPixmap.fromImage(q_image)
            self.pixmap_item.setPixmap(pixmap)
            self.ui.graphicsView.setSceneRect(0, 0, w, h)
            self.ui.graphicsView.fitInView(self.pixmap_item, Qt.KeepAspectRatio)

    def toggle_gray(self):
        """切换灰度化和恢复原色"""
        if self.image_current is not None:
            if not self.is_gray:
                gray_image = cv.cvtColor(self.image_current, cv.COLOR_BGR2GRAY)
                self.image_current = cv.cvtColor(gray_image, cv.COLOR_GRAY2BGR)
            else:
                self.image_current = self.image_original.copy()
            self.is_gray = not self.is_gray
            self.display_graphics_view()

    def invert_color(self):
        if self.image_current is not None:
            self.image_current = cv.bitwise_not(self.image_current)
            self.display_graphics_view()

    def rotate_image(self, angle):
        if self.image_current is not None:
            center = (self.image_current.shape[1] // 2, self.image_current.shape[0] // 2)
            matrix = cv.getRotationMatrix2D(center, angle, 1.0)
            rotated_image = cv.warpAffine(
                self.image_current,
                matrix,
                (self.image_current.shape[1], self.image_current.shape[0]),
                flags=cv.INTER_LINEAR,
            )
            self.image_current = rotated_image
            self.display_graphics_view()

    def showNewWindow(self):
        #global image_global # 将当前图像赋值给全局变量
        newwin.show()

class NewWindow(QWidget):
    def __init__(self):
        super(NewWindow, self).__init__()
        layout = QVBoxLayout(self)
        self.setWindowTitle('图像拖动与缩放')
        self.resize(800, 640)

        # 创建 QGraphicsView 实例
        self.graphics_view = CustomGraphicsView(self)
        self.image_viewer = CustomGraphicsView(self.graphics_view)


        self.button_open = QPushButton("传递图像", self)
        self.button_open.clicked.connect(self.openImage)
        layout.addWidget(self.button_open)
        layout.addWidget(self.image_viewer)  # 添加 ImageViewer 的 UI 到布局中
        self.setLayout(layout)

    def openImage(self):
        global filename_global
        if filename_global is not None:
            self.image_viewer.set_image(filename_global)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    viewer = ImageViewer(CustomGraphicsView())  # 传递一个 CustomGraphicsView 实例
    newwin = NewWindow()
    viewer.ui.show()
    sys.exit(app.exec())






